package com.xbongbong.paas.service.workflow.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xbongbong.coolapp.service.CoolAppCardService;
import com.xbongbong.formula.constant.Constant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.ext.FieldPermissionEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.NodeTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.enums.TaskTypeEnum;
import com.xbongbong.paas.feign.WorkOrderV2WorkflowFeignClient;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FlowStatusHelp;
import com.xbongbong.paas.help.FormDataHelp;
import com.xbongbong.paas.help.FormDataValidateDataHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.WorkflowNodeHelp;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.ValidateReturnPoJo;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.workflow.BeforeOperatorPojo;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowAddSignatureDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowBackDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowCommitAgainDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowCommitDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowRefuseDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowRevokeDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowSignatureItemDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowStorageDTO;
import com.xbongbong.paas.pojo.workflow.operate.dto.WorkflowTransferDTO;
import com.xbongbong.paas.pojo.workflow.operate.vo.WorkflowAddSignatureVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.WorkflowApprovalOperate;
import com.xbongbong.paas.service.dingtalkTodo.WorkflowDingtalkTodoService;
import com.xbongbong.paas.service.workflow.WorkflowApprovalOperatorService;
import com.xbongbong.paas.service.workflow.comment.WorkflowCommentPushMsgService;
import com.xbongbong.paas.service.workflow.trigger.WorkflowFormDataOperationService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.coolapp.pojo.dto.CoolAppWorkflowCardDTO;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.OutstockErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ProErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SettleAccountErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.WorkflowSetErrorCodeEnum;
import com.xbongbong.pro.enums.workflow.TriggerEventTypeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.service.toolbox.data.ProFormDataHelp;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.pro.workflow.enums.WorkflowOperateEnum;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.ProductConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.SettleAccountsEntity;
import com.xbongbong.saas.domain.entity.WorkOrderTemplateEntity;
import com.xbongbong.saas.domain.entity.ext.WorkOrderExplainEntityExt;
import com.xbongbong.saas.domain.entity.ext.WorkOrderFormEntityExt;
import com.xbongbong.saas.enums.SignTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.AssembleEnum;
import com.xbongbong.saas.enums.business.WorkOrderEnum;
import com.xbongbong.saas.help.AnalyticalHelp;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.model.SettleAccountsModel;
import com.xbongbong.saas.model.WorkOrderExplainModel;
import com.xbongbong.saas.model.WorkOrderFormModel;
import com.xbongbong.saas.model.WorkOrderTemplateModel;
import com.xbongbong.saas.service.toolbox.help.SaasSaveHelper;
import com.xbongbong.saas.toolbox.help.QuotationUtil;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import com.xbongbong.util.ApproveUtil;
import com.xbongbong.util.OwnerIdAndCoUserIdUtil;
import com.xbongbong.workflow.domain.entity.WorkflowEntity;
import com.xbongbong.workflow.domain.entity.WorkflowNodeEntity;
import com.xbongbong.workflow.domain.entity.WorkflowTaskEntity;
import com.xbongbong.workflow.domain.entity.WorkflowTaskNodeEntity;
import com.xbongbong.workflow.domain.entity.WorkflowTransferDataEntity;
import com.xbongbong.workflow.enums.WorkflowNodeTypeEnum;
import com.xbongbong.workflow.model.WorkflowModel;
import com.xbongbong.workflow.model.WorkflowNodeModel;
import com.xbongbong.workflow.model.WorkflowTaskModel;
import com.xbongbong.workflow.model.WorkflowTaskNodeModel;
import com.xbongbong.workflow.model.WorkflowTransferDataModel;
import com.xbongbong.workflow.pojo.Data;
import com.xbongbong.workflow.pojo.FlowDatas;
import com.xbongbong.workflow.pojo.User;
import com.xbongbong.workflow.pojo.WorkflowRabbitmqDTO;
import com.xbongbong.workflow.pojo.WorkflowTransferPOJO;
import com.xbongbong.workflow.pojo.nodes.ApprovalNode;
import com.xbongbong.workflow.producer.WorkflowProducer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 审批人工审批操作
 * @author 魏荣杰
 *
 */
@Service
@Slf4j
public class WorkflowApprovalOperatorServiceImpl implements WorkflowApprovalOperatorService {

    private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowApprovalOperatorServiceImpl.class);

    @Resource
    private WorkflowTaskNodeModel workflowTaskNodeModel;
    @Resource
    private WorkflowModel workflowModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private WorkflowCommentPushMsgService workflowCommentPushMsgService;
    @Resource
    private WorkflowTaskModel workflowTaskModel;
    @Resource
    private WorkflowNodeModel workflowNodeModel;
    @Resource
    private WorkflowApprovalOperate workflowApprovalOperate;
    @Resource
    private WorkflowTransferDataModel workflowTransferDataModel;
    @Resource
    private WorkflowDingtalkTodoService workflowDingtalkTodoService;
    @Resource
    private WorkflowFormDataOperationService workflowFormDataOperationService;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private WorkOrderExplainModel workOrderExplainModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private WorkOrderTemplateModel workOrderTemplateModel;
    @Resource
    private WorkOrderFormModel workOrderFormModel;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private SaasSaveHelper saasSaveHelper;
    @Resource
    private ProFormDataHelp proFormDataHelp;
    @Resource
    private UserModel userModel;
    @Resource
    private FormDataValidateDataHelp formDataValidateDataHelp;
    @Resource
    private AnalyticalHelp analyticalHelp;
    @Resource
    private WorkflowProducer workflowProducer;
    @Resource
    private FormDataHelp formDataHelp;
    @Resource
    private WorkflowNodeHelp workflowNodeHelp;
    @Resource
    private SettleAccountsModel settleAccountsModel;
    @Resource
    private CoolAppCardService coolAppCardService;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private WorkOrderV2WorkflowFeignClient workOrderV2WorkflowFeignClient;
    @Resource
    private FlowStatusHelp flowStatusHelp;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseVO commit(WorkflowCommitDTO workflowCommitDTO) throws XbbException {
        String corpid = workflowCommitDTO.getCorpid();
        String userId = workflowCommitDTO.getUserId();
        Long taskNodeId = workflowCommitDTO.getTaskNodeId();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity) || Objects.equals(workflowTaskNodeEntity.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }
        if ((!Objects.equals(workflowTaskNodeEntity.getTaskType(), TaskTypeEnum.UNTREATED.getType())
                && !Objects.equals(workflowTaskNodeEntity.getNodeType(), NodeTypeEnum.START_PROCESS_NODE.getNodeType()))
                || Objects.equals(TaskTypeEnum.COMMIT.getType(), workflowTaskNodeEntity.getTaskType())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_HAVE_DEAL);
        }

        // 并发锁
        String hashKey = corpid + StringConstant.UNDER_LINE + workflowTaskNodeEntity.getTaskId();

        try {
            if (Objects.nonNull(paasRedisHelper.getValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey))) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_IS_DEAL);
            }
            // 加锁
            paasRedisHelper.setValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey, true, RedisConstant.MICRO_DURATION);


            if (workflowCommitDTO.getImages() != null && !workflowCommitDTO.getImages().isEmpty()) {
                workflowTaskNodeEntity.setImages(JSON.toJSONString(workflowCommitDTO.getImages()));
            }
            if (workflowCommitDTO.getAttachmentList() != null && !workflowCommitDTO.getAttachmentList().isEmpty()) {
                workflowTaskNodeEntity.setAttachment(JSON.toJSONString(workflowCommitDTO.getAttachmentList()));
            }
            if (!StringUtil.isEmpty(workflowCommitDTO.getOpinion(), true)) {
                workflowTaskNodeEntity.setOpinion(workflowCommitDTO.getOpinion());
            }
            // at人处理
            if (workflowCommitDTO.getAtUserIds() != null && !workflowCommitDTO.getAtUserIds().isEmpty()) {
                workflowCommentPushMsgService.pushProcessComment(workflowCommitDTO.getLoginUser(), workflowTaskNodeEntity.getTaskId(), workflowCommitDTO.getAtUserIds());
            }
            WorkflowTransferDataEntity workflowTransferDataEntity = workflowTransferDataModel.getByTaskId(workflowTaskNodeEntity.getTaskId(), corpid);
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            BeanUtil.copyProperties(workflowCommitDTO, validateDataDTO);
            BeforeOperatorPojo beforeOperatorPojo = beforeOperator(validateDataDTO, workflowTaskNodeEntity, workflowCommitDTO.getDataList(), workflowTransferDataEntity);
            // 节点流转
            workflowApprovalOperate.commit(workflowCommitDTO, workflowTaskNodeEntity, beforeOperatorPojo, workflowTransferDataEntity);

            // 移除锁
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
        } catch (XbbException e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            throw e;
        } catch (Exception e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            log.error("com.xbongbong.workflow.service.approveListPage.impl.WorkflowApprovalOperatorServiceImpl.commit ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return new BaseVO();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseVO refuse(WorkflowRefuseDTO workflowRefuseDTO) throws XbbException {
        String corpid = workflowRefuseDTO.getCorpid();
        String userId = workflowRefuseDTO.getUserId();
        Long taskNodeId = workflowRefuseDTO.getTaskNodeId();


        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity) || Objects.equals(workflowTaskNodeEntity.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

        if (!Objects.equals(workflowTaskNodeEntity.getTaskType(), TaskTypeEnum.UNTREATED.getType())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_HAVE_DEAL);
        }

        // 并发锁
        String hashKey = corpid + StringConstant.UNDER_LINE + workflowTaskNodeEntity.getTaskId();

        try {
            if (Objects.nonNull(paasRedisHelper.getValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey))) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_IS_DEAL);
            }
            // 加锁
            paasRedisHelper.setValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey, true, RedisConstant.MICRO_DURATION);

            Long taskId = workflowTaskNodeEntity.getTaskId();
            if (workflowRefuseDTO.getImages() != null && !workflowRefuseDTO.getImages().isEmpty()) {
                workflowTaskNodeEntity.setImages(JSON.toJSONString(workflowRefuseDTO.getImages()));
            }
            if (workflowRefuseDTO.getAttachmentList() != null && !workflowRefuseDTO.getAttachmentList().isEmpty()) {
                workflowTaskNodeEntity.setAttachment(JSON.toJSONString(workflowRefuseDTO.getAttachmentList()));
            }
            if (!StringUtil.isEmpty(workflowRefuseDTO.getOpinion(), true)) {
                workflowTaskNodeEntity.setOpinion(workflowRefuseDTO.getOpinion());
            }
            // at人处理
            if (workflowRefuseDTO.getAtUserIds() != null && !workflowRefuseDTO.getAtUserIds().isEmpty()) {
                workflowCommentPushMsgService.pushProcessComment(workflowRefuseDTO.getLoginUser(), taskId, workflowRefuseDTO.getAtUserIds());
            }

            // 获取上下文
            WorkflowTransferDataEntity workflowTransferDataEntity = workflowTransferDataModel.getByTaskId(taskId, corpid);
            WorkflowTransferPOJO workflowTransferPOJO = JSON.parseObject(JSON.toJSONString(workflowTransferDataEntity.getData(), SerializerFeature.DisableCircularReferenceDetect), WorkflowTransferPOJO.class);

            workflowApprovalOperate.refuse(workflowTaskNodeEntity, false, workflowTransferPOJO, workflowRefuseDTO.getLoginUser());

            // 移除锁
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);

            // 酷应用操作
            CoolAppWorkflowCardDTO coolAppWorkflowCardDTO = new CoolAppWorkflowCardDTO(corpid, workflowRefuseDTO.getLoginUser(),
                    PlatFormEnum.INTERNAL.getValue(), null, workflowTaskNodeEntity.getAppId(), workflowTaskNodeEntity.getMenuId(), workflowTaskNodeEntity.getFormId(),
                    workflowTaskNodeEntity.getSaasMark(), workflowTaskNodeEntity.getBusinessType(), taskId, workflowTaskNodeEntity.getWorkflowId(), workflowTransferDataEntity.getDataId(),
                    FlowStatusEnum.REJECT.getType(), TaskTypeEnum.END.getType());
            coolAppCard(coolAppWorkflowCardDTO);
        } catch (XbbException e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            throw e;
        } catch (Exception e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            log.error("com.xbongbong.workflow.service.approveListPage.impl.WorkflowApprovalOperatorServiceImpl.refuse ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return new BaseVO();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseVO storage(WorkflowStorageDTO workflowStorageDTO) throws XbbException {
        String corpid = workflowStorageDTO.getCorpid();
        String userId = workflowStorageDTO.getUserId();
        Long taskNodeId = workflowStorageDTO.getTaskNodeId();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity) || Objects.equals(workflowTaskNodeEntity.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

        // 并发锁
        String hashKey = corpid + StringConstant.UNDER_LINE + workflowTaskNodeEntity.getTaskId();

        try {
            if (Objects.nonNull(paasRedisHelper.getValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey))) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_IS_DEAL);
            }
            // 加锁
            paasRedisHelper.setValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey, true, RedisConstant.MICRO_DURATION);


            WorkflowNodeEntity workflowNodeEntity = workflowNodeModel.getByKey(workflowTaskNodeEntity.getWorkflowNodeId(), corpid);
            if (Objects.isNull(workflowNodeEntity)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_NOT_EXIST);
            }
            WorkflowTransferDataEntity workflowTransferDataEntity = workflowTransferDataModel.getByTaskId(workflowTaskNodeEntity.getTaskId(), corpid);
            // 校验处理
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            BeanUtil.copyProperties(workflowStorageDTO, validateDataDTO);

            BeforeOperatorPojo beforeOperatorPojo = beforeOperator(validateDataDTO, workflowTaskNodeEntity, workflowStorageDTO.getDataList(), workflowTransferDataEntity);
            // 流转处理
            workflowApprovalOperate.storage(workflowStorageDTO, workflowTaskNodeEntity, beforeOperatorPojo, workflowTransferDataEntity);

            // 移除锁
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);

            // 酷应用操作
            CoolAppWorkflowCardDTO coolAppWorkflowCardDTO = new CoolAppWorkflowCardDTO(corpid, workflowStorageDTO.getLoginUser(),
                    PlatFormEnum.INTERNAL.getValue(), null, workflowTaskNodeEntity.getAppId(), workflowTaskNodeEntity.getMenuId(), workflowTaskNodeEntity.getFormId(),
                    workflowTaskNodeEntity.getSaasMark(), workflowTaskNodeEntity.getBusinessType(), workflowTaskNodeEntity.getTaskId(), workflowTaskNodeEntity.getWorkflowId(),
                    workflowTaskNodeEntity.getDataId() ,FlowStatusEnum.APPROVAL_PENDING.getType(), TaskTypeEnum.STORAGE.getType());
            coolAppCard(coolAppWorkflowCardDTO);
        } catch (XbbException e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            throw e;
        } catch (Exception e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            log.error("com.xbongbong.workflow.service.approveListPage.impl.WorkflowApprovalOperatorServiceImpl.storage", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

        return new BaseVO();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseVO transfer(WorkflowTransferDTO workflowTransferDTO) throws XbbException {
        String corpid = workflowTransferDTO.getCorpid();
        Long taskNodeId = workflowTransferDTO.getTaskNodeId();
        String userId = workflowTransferDTO.getUserId();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity) || Objects.equals(workflowTaskNodeEntity.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

//        if (!Objects.equals(workflowTaskNodeEntity.getTaskType(), TaskTypeEnum.UNTREATED.getType())) {
//            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_HAVE_DEAL);
//        }

        // 并发锁
        String hashKey = corpid + StringConstant.UNDER_LINE + workflowTaskNodeEntity.getTaskId();


        try {
            if (Objects.nonNull(paasRedisHelper.getValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey))) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_IS_DEAL);
            }
            // 加锁
            paasRedisHelper.setValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey, true, RedisConstant.MICRO_DURATION);

            if (workflowTransferDTO.getUserId().equals(workflowTransferDTO.getTransferUserId())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.TRANSFER_USER_NOT_TO_ME);
            }
            //判断系统转交的节点,如果传参不是未处理的，那么就是当前节点有离职的情况
            if(!Objects.equals(workflowTaskNodeEntity.getTaskType(), TaskTypeEnum.UNTREATED.getType())){
                //获取当前节点所有待处理taskNode
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put(ParameterConstant.CORPID, corpid);
                params.put(ParameterConstant.TASK_ID, workflowTaskNodeEntity.getTaskId());
                params.put("taskType", Constant.ZERO);
                params.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
                List<WorkflowTaskNodeEntity> entities = workflowTaskNodeModel.findEntities(params);
                if(CollectionsUtil.isNotEmpty(entities)){
                    workflowTaskNodeEntity = entities.get(0);
                }
            }
            workflowTaskNodeEntity.setTransferUserId(workflowTransferDTO.getTransferUserId());
            if (workflowTransferDTO.getImages() != null && !workflowTransferDTO.getImages().isEmpty()) {
                workflowTaskNodeEntity.setImages(JSON.toJSONString(workflowTransferDTO.getImages()));
            }
            if (workflowTransferDTO.getAttachmentList() != null && !workflowTransferDTO.getAttachmentList().isEmpty()) {
                workflowTaskNodeEntity.setAttachment(JSON.toJSONString(workflowTransferDTO.getAttachmentList()));
            }
            if (!StringUtil.isEmpty(workflowTransferDTO.getOpinion(), true)) {
               workflowTaskNodeEntity.setOpinion(workflowTransferDTO.getOpinion());
            }
            // at人处理
            if (workflowTransferDTO.getAtUserIds() != null && !workflowTransferDTO.getAtUserIds().isEmpty()) {
                workflowCommentPushMsgService.pushProcessComment(workflowTransferDTO.getLoginUser(), workflowTaskNodeEntity.getTaskId(), workflowTransferDTO.getAtUserIds());
            }
            WorkflowTransferDataEntity workflowTransferDataEntity = workflowTransferDataModel.getByTaskId(workflowTaskNodeEntity.getTaskId(), corpid);
// 校验处理
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            BeanUtil.copyProperties(workflowTransferDTO, validateDataDTO);
            BeforeOperatorPojo beforeOperatorPojo = beforeOperator(validateDataDTO, workflowTaskNodeEntity, workflowTransferDTO.getDataList(), workflowTransferDataEntity);
            workflowApprovalOperate.transfer(workflowTransferDTO, workflowTaskNodeEntity, workflowTransferDTO.getTransferUserId(), beforeOperatorPojo, workflowTransferDataEntity);
            // 移除锁
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            // 酷应用操作
            CoolAppWorkflowCardDTO coolAppWorkflowCardDTO = new CoolAppWorkflowCardDTO(corpid, workflowTransferDTO.getLoginUser(),
                    PlatFormEnum.INTERNAL.getValue(), null, workflowTaskNodeEntity.getAppId(), workflowTaskNodeEntity.getMenuId(), workflowTaskNodeEntity.getFormId(),
                    workflowTaskNodeEntity.getSaasMark(), workflowTaskNodeEntity.getBusinessType(), workflowTaskNodeEntity.getTaskId(), workflowTaskNodeEntity.getWorkflowId(),
                    workflowTaskNodeEntity.getDataId(), FlowStatusEnum.IN_APPROVAL.getType(), TaskTypeEnum.TRANSFER.getType());
            coolAppCard(coolAppWorkflowCardDTO);
        } catch (XbbException e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            throw e;
        } catch (Exception e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            log.error("com.xbongbong.workflow.service.approveListPage.impl.WorkflowApprovalOperatorServiceImpl.transfer", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return new BaseVO();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseVO revoke(WorkflowRevokeDTO workflowRevokeDTO) throws XbbException {
        String corpid = workflowRevokeDTO.getCorpid();
        String userId = workflowRevokeDTO.getUserId();
        Long taskNodeId = workflowRevokeDTO.getTaskNodeId();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity) || Objects.equals(workflowTaskNodeEntity.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

        // 并发锁
        String hashKey = corpid + StringConstant.UNDER_LINE + workflowTaskNodeEntity.getTaskId();

        try {
            if (Objects.nonNull(paasRedisHelper.getValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey))) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_IS_DEAL);
            }
            // 加锁
            paasRedisHelper.setValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey, true, RedisConstant.MICRO_DURATION);

            WorkflowTaskEntity workflowTaskEntity = workflowTaskModel.getByKey(workflowTaskNodeEntity.getTaskId(), corpid);

            List<PaasFormDataEntityExt> paasFormDataEntityExts = formDataHelp.getByDataIdList(Collections.singletonList(workflowTaskEntity.getDataId()), workflowTaskEntity.getBusinessType(), workflowTaskEntity.getSaasMark(), workflowTaskEntity.getFormId(), corpid);
            PaasFormDataEntityExt paasFormDataEntityExt = paasFormDataEntityExts.get(0);
            if (!Objects.equals(FlowStatusEnum.APPROVAL_PENDING.getType(), paasFormDataEntityExt.getFlowStatus())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_HAVE_DEAL);
            }

            workflowApprovalOperate.revoke(workflowTaskNodeEntity, workflowRevokeDTO.getUserId(), workflowRevokeDTO.getLoginUser());
            // 移除锁
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            // 酷应用操作
            CoolAppWorkflowCardDTO coolAppWorkflowCardDTO = new CoolAppWorkflowCardDTO(corpid, workflowRevokeDTO.getLoginUser(),
                    PlatFormEnum.INTERNAL.getValue(), null, workflowTaskNodeEntity.getAppId(), workflowTaskNodeEntity.getMenuId(), workflowTaskNodeEntity.getFormId(),
                    workflowTaskNodeEntity.getSaasMark(), workflowTaskNodeEntity.getBusinessType(), workflowTaskNodeEntity.getTaskId(), workflowTaskNodeEntity.getWorkflowId(),
                    workflowTaskNodeEntity.getDataId(), FlowStatusEnum.REVOKE.getType(), TaskTypeEnum.REVOKE.getType());
            coolAppCard(coolAppWorkflowCardDTO);
        } catch (XbbException e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            throw e;
        } catch (Exception e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            log.error("com.xbongbong.workflow.service.approveListPage.impl.WorkflowApprovalOperatorServiceImpl.revoke", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return new BaseVO();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseVO back(WorkflowBackDTO workflowBackDTO) throws XbbException {
        String corpid = workflowBackDTO.getCorpid();
        Long taskNodeId = workflowBackDTO.getTaskNodeId();
        String userId = workflowBackDTO.getUserId();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity) || Objects.equals(workflowTaskNodeEntity.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

        if (!Objects.equals(workflowTaskNodeEntity.getTaskType(), TaskTypeEnum.UNTREATED.getType())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_HAVE_DEAL);
        }

        // 并发锁
        String hashKey = corpid + StringConstant.UNDER_LINE + workflowTaskNodeEntity.getTaskId();


        try {
            if (Objects.nonNull(paasRedisHelper.getValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey))) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_IS_DEAL);
            }
            // 加锁
            paasRedisHelper.setValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey, true, RedisConstant.MICRO_DURATION);


            WorkflowNodeEntity nodeEntity = workflowNodeModel.getByKey(workflowTaskNodeEntity.getWorkflowNodeId(), corpid);

            WorkflowNodeEntity lastNode = workflowNodeHelp.findLastNode(nodeEntity);

            if (Objects.equals(lastNode.getType(), WorkflowNodeTypeEnum.START_NODE.getType())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.NOT_ALLOWED_TO_BACK);
            } else if (Objects.equals(lastNode.getType(), WorkflowNodeTypeEnum.CC_NODE.getType())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.NOT_ALLOWED_TO_BACK_CC);
            }

            if (workflowBackDTO.getImages() != null && !workflowBackDTO.getImages().isEmpty()) {
                workflowTaskNodeEntity.setImages(JSON.toJSONString(workflowBackDTO.getImages()));
            }
            if (workflowBackDTO.getAttachmentList() != null && !workflowBackDTO.getAttachmentList().isEmpty()) {
                workflowTaskNodeEntity.setAttachment(JSON.toJSONString(workflowBackDTO.getAttachmentList()));
            }
            if (!StringUtil.isEmpty(workflowBackDTO.getOpinion(), true)) {
                workflowTaskNodeEntity.setOpinion(workflowBackDTO.getOpinion());
            }
            // at人处理
            if (workflowBackDTO.getAtUserIds() != null && !workflowBackDTO.getAtUserIds().isEmpty()) {
                workflowCommentPushMsgService.pushProcessComment(workflowBackDTO.getLoginUser(), workflowTaskNodeEntity.getTaskId(), workflowBackDTO.getAtUserIds());
            }

            workflowApprovalOperate.back(workflowTaskNodeEntity,userId, lastNode);
            // 移除锁
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
        } catch (XbbException e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            throw e;
        } catch (Exception e) {
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            log.error("com.xbongbong.workflow.service.approveListPage.impl.WorkflowApprovalOperatorServiceImpl.back", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return new BaseVO();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseVO commitAgain(WorkflowCommitAgainDTO workflowCommitAgainDTO) throws XbbException {
        // 重新提交工作流
        String corpid = workflowCommitAgainDTO.getCorpid();
        Long taskNodeId = workflowCommitAgainDTO.getTaskNodeId();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity) || Objects.equals(workflowTaskNodeEntity.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

        if (Objects.equals(workflowTaskNodeEntity.getTaskType(), TaskTypeEnum.AGAIN_COMMIT.getType())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_HAVE_DEAL);
        }

        // 并发锁
        String hashKey = corpid + StringConstant.UNDER_LINE + workflowTaskNodeEntity.getTaskId();
        if (Objects.nonNull(paasRedisHelper.getValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey))) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_IS_DEAL);
        }
        // 加锁
        paasRedisHelper.setValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey, true, RedisConstant.MICRO_DURATION);





        // 发起新的工作流
        Long taskId = workflowTaskNodeEntity.getTaskId();
        if (commonHelp.isOpenWorkFlow(workflowCommitAgainDTO.getCorpid())) {
            // 开启工作流
            WorkflowTransferDataEntity workflowTransferDataEntity = workflowTransferDataModel.getByTaskId(taskId, corpid);
            WorkflowTransferPOJO transferPojo = JSON.parseObject(JSON.toJSONString(workflowTransferDataEntity.getData(), SerializerFeature.DisableCircularReferenceDetect), WorkflowTransferPOJO.class);


            WorkflowTransferPOJO workflowTransferPOJO = new WorkflowTransferPOJO();
            // data的编辑处理，绑定同一条dataId
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            BeanUtil.copyProperties(workflowCommitAgainDTO, validateDataDTO);
            BeforeOperatorPojo beforeOperatorPojo = beforeOperator(validateDataDTO, workflowTaskNodeEntity, workflowCommitAgainDTO.getDataList(), workflowTransferDataEntity);
            Data data = new Data(workflowTaskNodeEntity.getAppId(), workflowTaskNodeEntity.getMenuId(), workflowTaskNodeEntity.getFormId(), workflowTaskNodeEntity.getDataId(),
                    beforeOperatorPojo.getData(), workflowTaskNodeEntity.getBusinessType(), workflowTaskNodeEntity.getSaasMark(), null, transferPojo.getData().getSubBusinessType());

            User user = new User();
            BeanUtil.copyProperties(workflowCommitAgainDTO.getLoginUser(), user);
            workflowTransferPOJO.setUser(user);
            workflowTransferPOJO.setFlowDatas(new FlowDatas());
            workflowTransferPOJO.setCorpid(corpid);
            workflowTransferPOJO.setOperate(transferPojo.getOperate());
            workflowTransferPOJO.setTaskId(null);
            workflowTransferPOJO.setLogId(null);


            //要发起新的工作流，这边需要去匹配新的工作流
            Long workflowId = workflowTaskNodeEntity.getWorkflowId();
            WorkflowNodeEntity workflowNodeEntity = workflowNodeModel.getByUId(workflowId, corpid, "startNode");

            List<WorkflowEntity> satisfyTriggerEntitys = null;
            if (Objects.equals(transferPojo.getOperate(), WorkflowOperateEnum.ADD.getType())) {
                // 新建
                satisfyTriggerEntitys = workflowFormDataOperationService.getSatisfyTriggerEntitys(workflowNodeEntity.getCorpid(), workflowNodeEntity.getFormId(), workflowNodeEntity.getBusinessType(), Arrays.asList(TriggerEventTypeEnum.ONLY_ADD.getType(), TriggerEventTypeEnum.ADD_OR_UPDATE.getType()));

            } else if (Objects.equals(transferPojo.getOperate(), WorkflowOperateEnum.UPDATE.getType())) {
                // 编辑
                satisfyTriggerEntitys = workflowFormDataOperationService.getSatisfyTriggerEntitys(workflowNodeEntity.getCorpid(), workflowNodeEntity.getFormId(), workflowNodeEntity.getBusinessType(), Arrays.asList(TriggerEventTypeEnum.ONLY_UPDATE.getType(), TriggerEventTypeEnum.ADD_OR_UPDATE.getType()));
            } else if (Objects.equals(transferPojo.getOperate(), WorkflowOperateEnum.DELETE.getType())) {
                // 删除
                satisfyTriggerEntitys = workflowFormDataOperationService.getSatisfyTriggerEntitys(workflowNodeEntity.getCorpid(), workflowNodeEntity.getFormId(), workflowNodeEntity.getBusinessType(), Collections.singletonList(TriggerEventTypeEnum.ONLY_DELETE.getType()));
            }

            if (CollectionUtils.isNotEmpty(satisfyTriggerEntitys)) {
                WorkflowTaskNodeEntity updateTaskNode = new WorkflowTaskNodeEntity();
                //addSignature有默认值，手动置空
                updateTaskNode.setAddSignature(null);
                updateTaskNode.setTaskType(TaskTypeEnum.AGAIN_COMMIT.getType());
                updateTaskNode.setId(workflowTaskNodeEntity.getId());
                updateTaskNode.setCorpid(corpid);
                workflowTaskNodeModel.update(updateTaskNode);

                Long workflowStartId = satisfyTriggerEntitys.get(0).getId();
                WorkflowNodeEntity startNode = workflowNodeModel.getByUId(workflowStartId, corpid, "startNode");
                // 将开始节点id进行赋值
                data.setNodeId(startNode.getId());
                workflowTransferPOJO.setData(data);
                if (Objects.equals(transferPojo.getOperate(), WorkflowOperateEnum.ADD.getType())) {
                    // 将撤回或者拒绝的数据，重新更新回来
                    workflowApprovalOperate.updateData(workflowTransferPOJO, workflowTaskNodeEntity, beforeOperatorPojo, workflowCommitAgainDTO.getLoginUser(),TaskTypeEnum.AGAIN_COMMIT.getType());

                    PaasProcessDataEntity paasProcessDataEntity = new PaasProcessDataEntity();
                    paasProcessDataEntity.setCorpid(workflowTransferPOJO.getCorpid());
                    paasProcessDataEntity.setSaasMark(data.getSaasMark());
                    paasProcessDataEntity.setBusinessType(data.getBusinessType());
                    paasProcessDataEntity.setFormDataId(data.getId());
                    flowStatusHelp.updateFormDataStatus(paasProcessDataEntity, FlowStatusEnum.APPROVAL_PENDING.getType());
                }

                WorkflowRabbitmqDTO workflowRabbitmqDTO = new WorkflowRabbitmqDTO(workflowTransferPOJO, startNode, beforeOperatorPojo.getSaasNeedRedundantAttrPojo());
                workflowRabbitmqDTO.setPreTaskId(taskId);
                workflowProducer.startWorkflow(workflowRabbitmqDTO);
            } else {
                // 移除锁
                paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
                throw new XbbException(WorkflowSetErrorCodeEnum.API_ERROR_272002);
            }
        }


        // 钉钉待办处理
        WorkflowTaskEntity workflowTaskEntity = workflowTaskModel.getByKey(taskId, corpid);
        if (Objects.isNull(workflowTaskEntity)) {
            // 移除锁
            paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_TASK_NOT_EXIST);
        }
        // 删除时同步删除钉钉待办实例 会有覆盖实例id的情况，需要先删除钉钉实例
        if (Objects.nonNull(workflowTaskEntity.getDingtalkProcessInstanceId())) {
            workflowDingtalkTodoService.deleteDingtalkTodoInstance(corpid, workflowTaskEntity.getDingtalkProcessInstanceId());
        }

        // 移除锁
        paasRedisHelper.removeValue(RedisPrefixConstant.WORKFLOW_NODE_TASK, hashKey);

        return new BaseVO();
    }

    @Override
    public BaseVO addSignature(WorkflowAddSignatureDTO workflowAddSignatureDTO) throws XbbException {

        String corpid = workflowAddSignatureDTO.getCorpid();
        Long processTaskId = workflowAddSignatureDTO.getProcessTaskId();
        Long taskNodeId = workflowAddSignatureDTO.getTaskNodeId();
        Set<String> addUserIds = workflowAddSignatureDTO.getAddUserIds();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

        Map<String, Object> params = new HashMap<>();
        params.put(ParameterConstant.CORPID, corpid);
        params.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        params.put("taskId", processTaskId);
        params.put("nodeType", NodeTypeEnum.PROCESS_NODE.getNodeType());
        params.put("orderByStr", "id " + SortOrder.DESC + ", add_time " + SortOrder.DESC);

        List<WorkflowTaskNodeEntity> workflowTaskNodeEntityList = workflowTaskNodeModel.findEntities(params);

        //若当前节点已经通过了，则不允许加签
        Map<Integer, List<WorkflowTaskNodeEntity>> collect = workflowTaskNodeEntityList.stream().filter(v -> Objects.equals(v.getWorkflowNodeId(), workflowTaskNodeEntity.getWorkflowNodeId())).collect(Collectors.groupingBy(WorkflowTaskNodeEntity::getTaskType));
        if(!collect.keySet().contains(TaskTypeEnum.UNTREATED.getType())){
            //当前节点已经全部处理过了，不允许加签了
            throw new XbbException(ErrorCodeEnum.API_ERROR_209019);
        }

        // 回退节点
        List<WorkflowTaskNodeEntity> backNodeList = workflowTaskNodeEntityList.stream().filter(v -> Objects.equals(v.getTaskType(), TaskTypeEnum.BACK.getType())).sorted(Comparator.comparing(WorkflowTaskNodeEntity::getUpdateTime)).collect(Collectors.toList());
        Long recentBackTime = 0L;
        if(CollectionsUtil.isNotEmpty(backNodeList)){
            recentBackTime = backNodeList.get(0).getUpdateTime();
        }
        Long finalRecentBackTime = recentBackTime;
        //当前节点上所有的审批人
        Set<String> nowNodeUserIds = workflowTaskNodeEntityList.stream()
                .filter(v -> v.getAddTime() >= finalRecentBackTime)
                .filter(v -> Objects.equals(v.getWorkflowNodeId(), workflowTaskNodeEntity.getWorkflowNodeId()))
                .filter(v -> !Objects.equals(v.getTaskType(), TaskTypeEnum.TRANSFER.getType()) && !Objects.equals(v.getTaskType(), TaskTypeEnum.CC.getType()) && !Objects.equals(v.getTaskType(), TaskTypeEnum.WAIT_CC.getType()))
                .map(WorkflowTaskNodeEntity :: getUserId)
                .collect(Collectors.toSet());

        List<WorkflowTaskNodeEntity> workflowTaskNodeEntities = null;
        if(CollectionsUtil.isNotEmpty(nowNodeUserIds) && nowNodeUserIds.size() == Constant.ONE){
            //单人的时候，加签需要修改signType
            workflowTaskNodeEntities = workflowTaskNodeEntityList.stream()
                    .filter(v -> v.getAddTime() >= finalRecentBackTime)
                    .filter(v -> Objects.equals(v.getWorkflowNodeId(), workflowTaskNodeEntity.getWorkflowNodeId()))
                    .filter(v -> !Objects.equals(v.getTaskType(), TaskTypeEnum.TRANSFER.getType()) && !Objects.equals(v.getTaskType(), TaskTypeEnum.CC.getType()) && !Objects.equals(v.getTaskType(), TaskTypeEnum.WAIT_CC.getType()))
                    .filter(v -> nowNodeUserIds.contains(v.getUserId())).collect(Collectors.toList());
        }

        for (String addUserId : addUserIds) {
            if (nowNodeUserIds.contains(addUserId)) {
                throw new XbbException(ErrorCodeEnum.API_ERROR_209018);
            }
        }

        // 加签
        workflowApprovalOperate.addSignature(workflowAddSignatureDTO, workflowTaskNodeEntity, workflowTaskNodeEntities);


        return new BaseVO();
    }

    @Override
    public WorkflowAddSignatureVO signatureItem(@Valid WorkflowSignatureItemDTO workflowSignatureItemDTO) throws XbbException {
        WorkflowAddSignatureVO workflowAddSignatureVO = new WorkflowAddSignatureVO();

        String corpid = workflowSignatureItemDTO.getCorpid();
        Long processTaskId = workflowSignatureItemDTO.getProcessTaskId();
        Long taskNodeId = workflowSignatureItemDTO.getTaskNodeId();

        WorkflowTaskNodeEntity workflowTaskNodeEntity = workflowTaskNodeModel.getByKey(taskNodeId, corpid);
        if (Objects.isNull(workflowTaskNodeEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }

        Map<String, Object> params = new HashMap<>();
        params.put(ParameterConstant.CORPID, corpid);
        params.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        params.put("taskId", processTaskId);
        params.put("nodeType", NodeTypeEnum.PROCESS_NODE.getNodeType());
        params.put("orderByStr", "id " + SortOrder.DESC + ", add_time " + SortOrder.DESC);

        List<WorkflowTaskNodeEntity> workflowTaskNodeEntityList = workflowTaskNodeModel.findEntities(params);

        // 回退节点
        List<WorkflowTaskNodeEntity> backNodeList = workflowTaskNodeEntityList.stream().filter(v -> Objects.equals(v.getTaskType(), TaskTypeEnum.BACK.getType())).sorted(Comparator.comparing(WorkflowTaskNodeEntity::getUpdateTime)).collect(Collectors.toList());
        Long recentBackTime = 0L;
        if(CollectionsUtil.isNotEmpty(backNodeList)){
            recentBackTime = backNodeList.get(0).getUpdateTime();
        }
        Long finalRecentBackTime = recentBackTime;

        //获取当前节点所有taskNode
        List<WorkflowTaskNodeEntity> nowNodes = workflowTaskNodeEntityList.stream()
                .filter(v -> v.getAddTime() >= finalRecentBackTime)
                .filter(v -> Objects.equals(v.getWorkflowNodeId(), workflowTaskNodeEntity.getWorkflowNodeId()))
                .filter(v -> !Objects.equals(v.getTaskType(), TaskTypeEnum.TRANSFER.getType()) && !Objects.equals(v.getTaskType(), TaskTypeEnum.CC.getType()) && !Objects.equals(v.getTaskType(), TaskTypeEnum.WAIT_CC.getType()))
                .collect(Collectors.toList());

        WorkflowNodeEntity workflowNodeEntity = workflowNodeModel.getByKey(workflowTaskNodeEntity.getWorkflowNodeId(), corpid);
        if(Objects.isNull(workflowNodeEntity)){
            throw new XbbException(ProErrorCodeEnum.API_ERROR_260036);
        }
        ApprovalNode approvalNode = JSON.parseObject(workflowNodeEntity.getConfigData(), ApprovalNode.class);
        if (nowNodes.size() > 1) {
            if (Objects.equals(nowNodes.get(0).getSignType(), SignTypeEnum.ORSIGN.getValue())) {
                workflowAddSignatureVO.setSignTypes(Collections.singletonList(SignTypeEnum.ORSIGN.getValue()));
            } else {
                workflowAddSignatureVO.setSignTypes(Collections.singletonList(SignTypeEnum.COUNTERSIGN.getValue()));
            }
        } else {
            if(Objects.equals(approvalNode.getSignType(), SignTypeEnum.ORSIGN.getValue())){
                workflowAddSignatureVO.setSignTypes(Arrays.asList(SignTypeEnum.ORSIGN.getValue(), SignTypeEnum.COUNTERSIGN.getValue()));
            }else{
                workflowAddSignatureVO.setSignTypes(Arrays.asList(SignTypeEnum.COUNTERSIGN.getValue(), SignTypeEnum.ORSIGN.getValue()));
            }
        }


        return workflowAddSignatureVO;
    }


    private BeforeOperatorPojo beforeOperator(ValidateDataDTO validateDataDTO, WorkflowTaskNodeEntity workflowTaskNodeEntity, JSONObject dataList, WorkflowTransferDataEntity workflowTransferDataEntity) throws XbbException {
        try {
            String corpid = workflowTaskNodeEntity.getCorpid();
            Long formId = workflowTaskNodeEntity.getFormId();
            Integer businessType = workflowTaskNodeEntity.getBusinessType();
            Integer saasMark = workflowTaskNodeEntity.getSaasMark();
            Long workflowNodeId = workflowTaskNodeEntity.getWorkflowNodeId();
            WorkflowNodeEntity workflowNodeEntity = workflowNodeModel.getByKey(workflowNodeId, corpid);
            if (Objects.isNull(workflowNodeEntity)) {
                throw new XbbException(ProErrorCodeEnum.API_ERROR_260036);
            }
            validateDataDTO.setSaasMark(workflowNodeEntity.getSaasMark());
            validateDataDTO.setBusinessType(workflowNodeEntity.getBusinessType());
            validateDataDTO.setAppId(workflowNodeEntity.getAppId());
            validateDataDTO.setFormId(workflowNodeEntity.getFormId());
            validateDataDTO.setMenuId(workflowNodeEntity.getMenuId());
            ApprovalNode approvalNode = JSON.parseObject(workflowNodeEntity.getConfigData(), ApprovalNode.class);
            // 节点权限
            Map<String, FieldPermissionEntityExt> fieldPermissionMap = approvalNode.getFieldPermission();
            JSONObject saasNeedPojo = workflowTransferDataEntity.getSaasNeedPojo();
            // 获取字段解释
            boolean isFree = false;
            List<FieldAttrEntity> explainList;
            if (Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode())) {
                WorkOrderExplainEntityExt workOrderExplainEntityExt = workOrderExplainModel.getByFormId(formId, corpid);
                if (workOrderExplainEntityExt == null) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                }
                explainList = JSON.parseArray(workOrderExplainEntityExt.getExplains(), FieldAttrEntity.class);
                WorkOrderFormEntityExt workOrderEntity = workOrderFormModel.getByKey(formId, corpid);
                WorkOrderTemplateEntity workOrderTemplateEntity = workOrderTemplateModel.getBykey(workOrderEntity.getTemplateId(), corpid);
                isFree = Objects.equals(workOrderTemplateEntity.getIsFree(), 1);
            } else {
                PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
                explainList = JSON.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
            }
            explainList.forEach(item->{
                Integer fieldType = item.getFieldType();
                if (Objects.equals(fieldType, FieldTypeEnum.LABEL.getType())){
                    JSONArray jsonArray = dataList.getJSONArray(item.getAttr());
                    JSONArray jsonArray1 = new JSONArray();
                    if (CollectionsUtil.isNotEmpty(jsonArray)) {
                        for (Object o : jsonArray) {
                            if ( o instanceof Map ) {
                                JSONObject jsonObject = (JSONObject)o;
                                jsonArray1.add(jsonObject.getLong("id"));
                            }
                        }
                        dataList.put(item.getAttr(),jsonArray1);
                    }
                }
            });
            PaasFormDataEntity oldFormData = proFormDataHelp.getFormData(corpid, saasMark, businessType, workflowTaskNodeEntity.getDataId());

            Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMapByList(explainList);
            if (Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode()) && !isFree) {
                explainMap.get(WorkOrderEnum.MANAGER_ID.getAttr()).setVisible(0);
            }
            // 根据字段权限设置可见规则
            ApproveUtil.setVisibleByFieldPermission(explainMap, fieldPermissionMap);

            //发票、回款单金额明细处理
            SheetTypeEnum sheetTypeEnum = fundHelp.getSheetTypeEnumByProcssData(businessType, dataList);
            JSONArray amountDetail = saasSaveHelper.getAmountDetail4Check(workflowTaskNodeEntity.getDataId(), sheetTypeEnum, dataList,businessType);
            //在此处就提前获取，防止在内部方法被置入了新的data
            // 数据格式校验
            validateDataDTO.setExplainMap(explainMap);
            validateDataDTO.setAmountDetail(amountDetail);
            validateDataDTO.setDataId(workflowTaskNodeEntity.getDataId());
            validateDataDTO.setData(dataList);
            ProSaveHelp.analyticalData(validateDataDTO);
            boolean isCreatorIdExist = false;
            String creatorId = oldFormData.getCreatorId();
            if ( StringUtil.isNotEmpty(creatorId) ) {
                UserEntity userEntity = userModel.getByKey(creatorId, corpid);
                if ( Objects.nonNull(userEntity) ) {
                    String creatorUserId = userEntity.getUserId();
                    if (Objects.equals(creatorUserId, creatorId) ) {
                        isCreatorIdExist = true;
                    }
                }
            }
            validateDataDTO.setTaskId(workflowTaskNodeEntity.getTaskId());
            if (!isCreatorIdExist ) {
                creatorId = null;
            }
            validateDataDTO.setCreatorId(creatorId);
            validateDataDTO.setProcessCreatorId(creatorId);
            if (StringUtil.isNotEmpty(creatorId)) {
                //  在此处增加流程创建人权限获取等相关操作，避免在com.xbongbong.saas.service.toolbox.help.UserTeamHelp.specialBusinessHandle增加
                UserVO userVO = userModel.getUserVO(corpid, creatorId, true, true);
                validateDataDTO.setLoginUser(userVO);
            }
            Integer newVersion = QuotationUtil.setSpecialParam(businessType,  dataList);
            validateDataDTO.setNewVersion(newVersion);
            validateDataDTO.setFormDataId(oldFormData.getDataId());
            validateDataDTO.setDataId(oldFormData.getDataId());
            formDataValidateDataHelp.validateData(validateDataDTO);
            //进销存业务校验
            if (ProductConstant.EFFECT_PRODUCT_COST_AND_STOCK.contains(businessType)) {
                //新建
                Long dataId = validateDataDTO.getDataId();
                boolean isNew = analyticalHelp.isNew(dataId,validateDataDTO.getTaskId(),corpid);
                if (isNew){
                    //结账校验
                    JSONObject data = validateDataDTO.getData();
                    Long date= data.getLong(AssembleEnum.ASSEMBLE_TIME.getAttr());
                    //结账中校验
                    String redisHelperValue = paasRedisHelper.getValue(RedisPrefixConstant.SETTLE_ACCOUNTS, corpid);
                    if (StringUtil.isNotEmpty(redisHelperValue)) {
                        if (date <= DateTimeUtil.getTodayEndInt(Long.valueOf(redisHelperValue))){
                            throw new XbbException(SettleAccountErrorCodeEnum.API_ERROR_254007);
                        }
                    }
                    SettleAccountsEntity accountsEntity = settleAccountsModel.getLastSettleAccounts(corpid);
                    //校验日期是否受结账限制
                    if (Objects.nonNull(accountsEntity) && Objects.nonNull(accountsEntity.getCheckOutTime())) {
                        if (date <= DateTimeUtil.getTodayEndInt(accountsEntity.getCheckOutTime())) {
                            throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212051);
                        }
                    }
                }
            }
            // SaaS业务特殊处理
            if (Objects.equals(saasMark, SaasMarkEnum.SAAS.getCode())) {
                Map<String, List<ReturnUserAndDepartmentPojo>> resultMap = OwnerIdAndCoUserIdUtil.setOwnIdAndCoUserId(dataList);
                validateDataDTO.setOwnerIds(resultMap.get(FieldTypeEnum.OWNERID.getAlias()));
                validateDataDTO.setCoUserId(resultMap.get(FieldTypeEnum.COUSERID.getAlias()));
                //审批中的isImport的值一直为空，考虑到这个地方目前不可能出现审批导入的情况，所以吧这个置为0
                validateDataDTO.setIsImport(0);
            } else {
                Map<String, List<ReturnUserAndDepartmentPojo>> resultMap = OwnerIdAndCoUserIdUtil.setOwnIdAndCoUserId(dataList);
                validateDataDTO.setOwnerIds(resultMap.get(FieldTypeEnum.OWNERID.getAlias()));
                validateDataDTO.setCoUserId(resultMap.get(FieldTypeEnum.COUSERID.getAlias()));
            }
            //这边新增团队的时候需要判断是新增还是编辑的
            validateDataDTO.setIsNew(Objects.equals(workflowTransferDataEntity.getOperate(), WorkflowOperateEnum.ADD.getType()));
            if (XbbRefTypeEnum.workOrderV2SupportApproval().contains(validateDataDTO.getBusinessType())) {
                XbbResponse<ValidateReturnPoJo> xbbResponse = workOrderV2WorkflowFeignClient.analytical(validateDataDTO, LocaleContextHolder.getLocale().toString());
                if (!xbbResponse.isSuccess()) {
                    throw new XbbException(xbbResponse.getCode(), xbbResponse.getMsg());
                }
                ValidateReturnPoJo validateReturnPoJo = xbbResponse.getResult();
                validateDataDTO.setSaasNeedRedundantAttrPoJo(validateReturnPoJo.getSaasNeedRedundantAttrPoJo());
                validateDataDTO.setData(validateReturnPoJo.getData());
                validateDataDTO.setDepartmentId(validateReturnPoJo.getDepartmentId());
                validateDataDTO.setFromApproval(validateDataDTO.getFromApproval());
                validateDataDTO.setVisbleUser(validateReturnPoJo.getVisbleUser());
                validateDataDTO.setVisbleDept(validateReturnPoJo.getVisbleDept());
             } else {
                analyticalHelp.beforeSave(validateDataDTO);
            }
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = validateDataDTO.getSaasNeedRedundantAttrPoJo();
            saasNeedRedundantAttrPojo = saasNeedRedundantAttrPojo == null ? new SaasNeedRedundantAttrPojo() : saasNeedRedundantAttrPojo;
            BeforeOperatorPojo beforeOperatorPojo = new BeforeOperatorPojo();
            saasNeedRedundantAttrPojo.setAmountDetail(amountDetail);
            if (Objects.nonNull(saasNeedPojo)) {
                saasNeedRedundantAttrPojo.setRefundId(saasNeedPojo.getLong("refundId"));
                saasNeedRedundantAttrPojo.setReturnedPurchaseId(saasNeedPojo.getLong("returnedPurchaseId"));
            }
            beforeOperatorPojo.setSaasNeedRedundantAttrPojo(saasNeedRedundantAttrPojo);
            validateDataDTO.getData().put(FieldTypeEnum.DEPARTMENTID.getAlias(), validateDataDTO.getDepartmentId());
            beforeOperatorPojo.setData(validateDataDTO.getData());
            beforeOperatorPojo.setHttpHeader(validateDataDTO.getHttpHeader());
            beforeOperatorPojo.setVisbleDept(validateDataDTO.getVisbleDept());
            beforeOperatorPojo.setVisbleUser(validateDataDTO.getVisbleUser());
            return beforeOperatorPojo;
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.error("com.xbongbong.workflow.service.approveListPage.impl.WorkflowApprovalOperatorServiceImpl.beforeOperator", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    /**
     * 触发酷应用
     *
     * @param coolAppWorkflowCardDTO
     */
    private void coolAppCard(CoolAppWorkflowCardDTO coolAppWorkflowCardDTO) {
        Runnable runnable = () -> {
            try {
                coolAppWorkflowCardDTO.setOpenConversationId(null);
                coolAppCardService.updateWorkflowCard(coolAppWorkflowCardDTO);
            } catch (Exception e) {
                LOGGER.error("更新酷应用卡片失败", e);
            }
        };
        threadPoolBeanConfig.interactiveCardThreadPool().execute(runnable);
    }
}
